package com.utils.httpclient;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;

/**
 * HTTPCLIENT池管理者创建类
 * <p>
 * 后续版本考虑个性化配置
 */
public class HttpClientPoolManagerBuilder {

    private PoolingHttpClientConnectionManager connManager = null;

    private HttpClientPoolManagerBuilder() {
        connManager = new PoolingHttpClientConnectionManager();
        connManager.setMaxTotal(2000);
        // 设置每个连接的路由数
        connManager.setDefaultMaxPerRoute(2000);
    }

    private static class Assistant {
        final static HttpClientPoolManagerBuilder builder = new HttpClientPoolManagerBuilder();
    }

    public static HttpClientPoolManagerBuilder build() {
        return Assistant.builder;
    }

    public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
        return this.connManager;
    }

    /**
     * 获取HTTPCLIENT
     *
     * @param requestConfig
     * @return
     */
    public CloseableHttpClient buildHttpClient(RequestConfig requestConfig) {
        return HttpClients.custom()
                // 把请求相关的超时信息设置到连接客户端
                .setDefaultRequestConfig(requestConfig)
                // 把请求重试设置到连接客户端
                .setRetryHandler(null)
                // 配置连接池管理对象
                .setConnectionManager(connManager)
                .build();
    }

    /**
     * 获取HTTPCLIENT 重试策略
     *
     * @return
     */
    public HttpRequestRetryHandler buildHttpClientRetryHandler() {
        HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 3) {// 如果已经重试了3次，就放弃
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return true;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;
                }
                if (exception instanceof SSLException) {// ssl握手异常
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的，就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
        return retry;
    }
}
